package com.io.netty.groupchat;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

public class ChatServer {

    private int PORT=9879;

    public ChatServer(int PORT) {
        this.PORT=PORT;
    }

    public void run() throws Exception {

        //表示只有一个线程维护bossGroup（也就是只有1个线程来管理客户端的连接请求）
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        //默认是cpu核数*2，也就是8个线程来维护workerGroup（也就是有8个线程来管理客户端的channel的IO）
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup)
                    .option(ChannelOption.SO_BACKLOG, 128)//队列中最多放入128个客户端channel
                    .childOption(ChannelOption.SO_KEEPALIVE, true)//保持channel为活跃状态
                    //服务器端端的通道类型（是一个实现类）
                    .channel(NioServerSocketChannel.class)
                    //客户端与服务器端用来传递数据的通道，客户端与服务器端泛型都是SocketChannel接口
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //netty提供的字符串解码器处理器
                            ch.pipeline().addLast("decoder",new StringDecoder());
                            //netty提供的字符串编码器处理器
                            ch.pipeline().addLast("encoder",new StringEncoder());
                            //自定义的处理器
                            ch.pipeline().addLast(new ChatServerHandler());
                        }
                    });
            System.out.println("服务器启动。。。。");
            //主线程不会阻塞在这，这个同步的等待是由bossGroup线程来完成的
            ChannelFuture channelFuture = serverBootstrap.bind(PORT).sync();

            //同步监听通道的关闭
            //如果是异步，就会直接执行finally代码块中的内容，通道还没关线程就直接关了，代码不会有问题吗
            //会有问题，会交互失败
            //如果是同步，线程就会阻塞在这等待关闭命令，那么效率不是变低了吗？这一点不是很理解。。。
            //是同步的，主线程会阻塞在这，等待通道的关闭
            channelFuture.channel().closeFuture().sync();
        }finally {
            //关闭线程组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception{
        new ChatServer(9879).run();
    }
}
